package com.best.member.serice.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.CollectionUtils;

import com.best.core.constants.CommonConstants;
import com.best.core.entity.CommonResult;
import com.best.core.entity.CommonStatusCode;
import com.best.core.utils.*;
import com.best.member.client.WeiXinClient;
import com.best.member.input.dto.UserLoginInpDTO;
import com.best.member.input.dto.UserRegisterDTO;
import com.best.member.mapper.UserPOMapper;
import com.best.member.mapper.UserTokenPOMapper;
import com.best.member.output.dto.UserOutputDTO;
import com.best.member.po.UserPO;
import com.best.member.po.UserPOExample;
import com.best.member.po.UserTokenPO;
import com.best.member.po.UserTokenPOExample;
import com.best.member.serice.MemberService;
import com.best.member.utils.MultiTransactionManager;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName: MemberServiceImpl
 * @Package: com.best.member.serice.impl
 * @Description: 会员业务层接口实现类
 * @Datetime: 2020/6/10 15:17
 * @Author: nike
 */
@Slf4j
@Service
public class MemberServiceImpl implements MemberService {

    @Autowired
    private UserPOMapper userPOMapper;
    @Autowired
    private UserTokenPOMapper userTokenPOMapper;
    @Autowired
    private GenerateToken generateToken;
    @Autowired
    private MultiTransactionManager multiTransactionManager;
    @Autowired
    private WeiXinClient weiXinClient;
    @Autowired
    private IdWorker idWorker;

    @Override
    public CommonResult register(UserRegisterDTO userRegisterDTO) {
        String passwordMd5 = MD5Utils.MD5(userRegisterDTO.getPassword());
        userRegisterDTO.setPassword(passwordMd5);

        // 校验注册码
        // CommonResult commonResult = weiXinClient.verifyCode(userRegisterDTO.getMobile(),
        // userRegisterDTO.getRegistCode());
        // if (!commonResult.getCode().equals(CommonStatusCode.OK)) {
        // return CommonResult.buildFail(commonResult.getMsg());
        // }
        // 实体转换
        UserPO userPO = BeanUtils.copy(userRegisterDTO, UserPO.class);
        Date nowDate = new Date();
        userPO.setCreateTime(nowDate);
        userPO.setUserId(idWorker.nextId());
        int registerResult = userPOMapper.insertSelective(userPO);

        int i = 1 / 0;

        return registerResult > 0 ? CommonResult.buildSuccess("注册成功!")
                : CommonResult.buildFail("注册失败!");
    }

    @Override
    public CommonResult<UserOutputDTO> verifyMobile(String mobile) {
        UserPOExample example = new UserPOExample();
        UserPOExample.Criteria criteria = example.createCriteria();
        criteria.andMobileEqualTo(mobile);
        List<UserPO> userPOS = userPOMapper.selectByExample(example);

        if (CollectionUtils.isEmpty(userPOS)) {
            return CommonResult.buildFail(false, CommonStatusCode.NOT_EXIST, "用户不存在!");
        }
        // 处理返回数据
        UserPO userPO = userPOS.get(0);
        UserOutputDTO outputDTO = BeanUtils.copy(userPO, UserOutputDTO.class);

        return CommonResult.buildSuccess(outputDTO);
    }

    @Override
    public CommonResult login(UserLoginInpDTO userLoginInpDTO, String ipAddr) {
        String mobile = userLoginInpDTO.getMobile();
        String password = userLoginInpDTO.getPassword();
        // 登录类型
        String loginType = userLoginInpDTO.getLoginType();
        // 设备信息
        String deviceInfor = userLoginInpDTO.getDeviceInfor();
        String passwordMd5 = MD5Utils.MD5(password);
        // 根据手机号与密码查询
        UserPOExample example = new UserPOExample();
        UserPOExample.Criteria criteria = example.createCriteria();
        criteria.andMobileEqualTo(mobile);
        criteria.andPasswordEqualTo(passwordMd5);
        List<UserPO> userPOS = userPOMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(userPOS)) {
            return CommonResult.buildFail("手机号码或密码错误!");
        }


        // 事务对象
        TransactionStatus transactionStatus = null;

        try {
            UserPO userPO = userPOS.get(0);
            // 查询之前是否有过登录
            Long userId = userPO.getUserId();
            UserTokenPOExample tokenPOExample = new UserTokenPOExample();
            UserTokenPOExample.Criteria tokenPOExampleCriteria = tokenPOExample.createCriteria();
            tokenPOExampleCriteria.andUserIdEqualTo(userId);
            tokenPOExampleCriteria.andIsAvalibleEqualTo(CommonConstants.ENABLE_AVALIBLE);
            tokenPOExampleCriteria.andLoginTypeEqualTo(loginType);
            List<UserTokenPO> userTokenPOS = userTokenPOMapper.selectByExample(tokenPOExample);

            // 开启手动事务
            transactionStatus = multiTransactionManager.begin();

            if (!CollectionUtils.isEmpty(userTokenPOS)) {
                // 清楚之前的token
                for (UserTokenPO redisTokenPO : userTokenPOS) {
                    // 清除redis之前的token
                    Boolean removeToken = generateToken.removeToken(redisTokenPO.getToken());
                    // 更新之前的token为不可用
                    UserTokenPOExample tokenPOExampleupdate = new UserTokenPOExample();
                    UserTokenPOExample.Criteria exampleupdateCriteria =
                            tokenPOExampleupdate.createCriteria();
                    exampleupdateCriteria.andTokenEqualTo(redisTokenPO.getToken());
                    exampleupdateCriteria.andUserIdEqualTo(redisTokenPO.getUserId());

                    UserTokenPO tokenPO = new UserTokenPO();
                    tokenPO.setIsAvalible(CommonConstants.UNENABLE_AVALIBLE);
                    tokenPO.setUpdateTime(new Date());

                    userTokenPOMapper.updateByExampleSelective(tokenPO, tokenPOExampleupdate);
                }
            }

            // 生成新的token,token生成规则：前缀.登录类型.手机号.随机码
            String keyPrefix =
                    CommonConstants.MEMBER_TOKEN_KEYPREFIX + "." + loginType + "." + mobile;
            String token = generateToken.createToken(keyPrefix, userId + "",
                    CommonConstants.MEMBRE_LOGIN_TOKEN_TIME);

            // 将token存入数据库
            UserTokenPO po = new UserTokenPO();
            po.setId(idWorker.nextId());
            po.setUserId(userId);
            po.setToken(token);
            po.setLoginType(loginType);
            po.setDeviceInfor(deviceInfor);
            po.setCreateTime(new Date());
            po.setIsAvalible(CommonConstants.ENABLE_AVALIBLE);
            po.setLoginIp(ipAddr);

            userTokenPOMapper.insertSelective(po);

            Map<String, String> tokenMap = new HashMap<>();
            tokenMap.put("token", token);

            // 事务提交
            multiTransactionManager.commit(transactionStatus);

            return CommonResult.buildSuccess(tokenMap);
        } catch (Exception e) {
            // 事务回滚
            multiTransactionManager.rollback(transactionStatus);
            return CommonResult.buildFail("系统异常，稍后再试!");
        }
    }

    @Override
    public CommonResult<UserOutputDTO> getUserInfo(String token) {
        // 校验
        if (StringUtils.isEmpty(token)) {
            return CommonResult.buildFail("token不能为空!");
        }
        // 获取token对应的userId
        String value = generateToken.getToken(token);
        if (StringUtils.isEmpty(value)) {
            return CommonResult.buildFail("token已经失效或不正确!");
        }

        long userId = TypeCastUtils.toLong(value);
        // 查询用户信息
        UserPO userPO = userPOMapper.selectByPrimaryKey(userId);
        if (null == userPO) {
            return CommonResult.buildFail("用户信息不存在!");
        }
        // 实体转换
        UserOutputDTO userOutputDTO = BeanUtils.copy(userPO, UserOutputDTO.class);

        return CommonResult.buildSuccess(userOutputDTO);
    }

    public static void main(String[] args) {
        String s = MD5Utils.MD5("123456");
        System.out.printf(s);

        GenerateToken generateToken = new GenerateToken();

        Boolean removeToken = generateToken
                .removeToken("PC.best.shop.member.logine00f7797f1134953b031b945542df36e");

        System.out.printf(removeToken + "");
    }

    public void testRedis() {
        Boolean removeToken = generateToken
                .removeToken("PC.best.shop.member.logine00f7797f1134953b031b945542df36e");
        log.info("redis ：{}", removeToken);
    }
}
